package juego.sprites;

import java.awt.Graphics;

import javax.swing.ImageIcon;

import juego.util.Coordenadas2D;

public abstract class EntidadMovil extends Entidad {
	
	protected Coordenadas2D velocidad;
	protected Coordenadas2D aceleracion;
	private Animacion animIzquierda;
	private Animacion animDerecha;
	private Animacion animArriba;
	private Animacion animAbajo;
	private Animacion animIzqArr;
	private Animacion animIzqAba;
	private Animacion animDerArr;
	private Animacion animDerAba;
	private boolean animDiagonales;
	
	public EntidadMovil(boolean animDiagonales, int duracionEtapaAnim) {
		super(duracionEtapaAnim);
		this.velocidad = new Coordenadas2D();
		this.aceleracion = new Coordenadas2D(0.0, 0.0);
		this.animDiagonales = animDiagonales;
		this.animIzquierda = new Animacion(duracionEtapaAnim);
		this.animDerecha = new Animacion(duracionEtapaAnim);
		this.animArriba = new Animacion(duracionEtapaAnim);
		this.animAbajo = new Animacion(duracionEtapaAnim);
		if (animDiagonales) {
			this.animIzqArr = new Animacion(duracionEtapaAnim);
			this.animDerArr = new Animacion(duracionEtapaAnim);
			this.animIzqAba = new Animacion(duracionEtapaAnim);
			this.animDerAba = new Animacion(duracionEtapaAnim);
		}
	}
	
	public EntidadMovil(int posX, int posY, boolean animDiagonales, int duracionEtapaAnim) {
		super(posX, posY, duracionEtapaAnim);
		this.velocidad = new Coordenadas2D();
		this.aceleracion = new Coordenadas2D(0, 1000);
		this.animDiagonales = animDiagonales;
		this.animIzquierda = new Animacion(duracionEtapaAnim);
		this.animDerecha = new Animacion(duracionEtapaAnim);
		this.animArriba = new Animacion(duracionEtapaAnim);
		this.animAbajo = new Animacion(duracionEtapaAnim);
		if (animDiagonales) {
			this.animIzqArr = new Animacion(duracionEtapaAnim);
			this.animDerArr = new Animacion(duracionEtapaAnim);
			this.animIzqAba = new Animacion(duracionEtapaAnim);
			this.animDerAba = new Animacion(duracionEtapaAnim);
		}
	}
	
	public EntidadMovil(int posX, int posY, float velocidadMovimiento, boolean animDiagonales, int duracionEtapaAnim) {
		this(posX, posY, animDiagonales, duracionEtapaAnim);
	}
	
	/**
	 * Devuelve la posicion en el eje X a la que se moveria esta EntidadMovil si se llamara al metodo
	 * <code>moverX(double dt)</code>
	 * @param dt
	 * @return
	 */
	public double calcularNuevaPosX(double dt) {
		double v = (aceleracion.getX() * dt + velocidad.getX());
		if (v < -500) v = -500;
		if (v >  500) v =  500;
		
		return (0.5 * aceleracion.getX() * dt * dt + v * dt + posicion.getX());
	}
	
	/**
	 * Devuelve la posicion en el eje Y a la que se moveria esta EntidadMovil si se llamara al metodo
	 * <code>moverY(double dt)</code>
	 * @param dt
	 * @return
	 */
	public double calcularNuevaPosY(double dt) {
		double v = (aceleracion.getY() * dt + velocidad.getY());
		if (v < -500) v = -500;
		if (v >  500) v =  500;
		
		return (0.5 * aceleracion.getY() * dt * dt + v * dt + posicion.getY());
	}
	
	/**
	 * Mueve el objeto en funcion de su posicion actual, su velocidad y su aceleracion en el eje X.
	 * @param dt
	 */
	public void moverX(double dt) {
		velocidad.setX(aceleracion.getX() * dt + velocidad.getX());
		if (velocidad.getX() < -500) {
			velocidad.setX(-500);
		}
		if (velocidad.getX() > 500) {
			velocidad.setX(500);
		}
		posicion.setX(0.5 * aceleracion.getX() * dt * dt + velocidad.getX() * dt + posicion.getX());
	}
	
	/**
	 * Mueve el objeto en funcion de su posicion actual, su velocidad y su aceleracion en el eje Y.
	 * @param dt
	 */
	public void moverY(double dt) {
		velocidad.setY(aceleracion.getY() * dt + velocidad.getY());
		if (velocidad.getY() < -500) {
			velocidad.setY(-500);
		}
		if (velocidad.getY() > 500) {
			velocidad.setY(500);
		}
		posicion.setY(0.5 * aceleracion.getY() * dt * dt + velocidad.getY() * dt + posicion.getY());
	}
	
	/**
	 * Aplica la reaccion ante una colision con el mapa en el eje X.
	 */
	public abstract void gestionarColisionMapaX();
	
	/**
	 * Aplica la reaccion ante una colision con el mapa en el eje Y.
	 */
	public abstract void gestionarColisionMapaY();
	
	@Override
	/**
	 * Actualiza la animacion de esta EntidadMovil.
	 * Llama a <code>actualizarAnimacion(double dt)</code> de la superclase.
	 */
	public void actualizarAnimacion(double dt) {
		if ((velocidad.getX() == 0) && (velocidad.getY() == 0) && super.getAnimacionPorDefecto().getNumEtapas() > 0) {
			super.actualizarAnimacion(dt);
			animIzquierda.reiniciar();
			animDerecha.reiniciar();
			animArriba.reiniciar();
			animAbajo.reiniciar();
			animIzqAba.reiniciar();
			animIzqArr.reiniciar();
			animDerAba.reiniciar();
			animDerArr.reiniciar();
			return;
		}
		if (animDiagonales) {
			if ((velocidad.getX() < 0) && (velocidad.getY() < 0) && (animIzqArr.getNumEtapas() > 0)) {
				super.getAnimacionPorDefecto().reiniciar();
				animIzquierda.reiniciar();
				animDerecha.reiniciar();
				animArriba.reiniciar();
				animAbajo.reiniciar();
				animIzqAba.reiniciar();
				animIzqArr.actualizar(dt);
				animDerAba.reiniciar();
				animDerArr.reiniciar();
				return;
			}
			if ((velocidad.getX() > 0) && (velocidad.getY() < 0) && (animDerArr.getNumEtapas() > 0)) {
				super.getAnimacionPorDefecto().reiniciar();
				animIzquierda.reiniciar();
				animDerecha.reiniciar();
				animArriba.reiniciar();
				animAbajo.reiniciar();
				animIzqAba.reiniciar();
				animIzqArr.reiniciar();
				animDerAba.reiniciar();
				animDerArr.actualizar(dt);
				return;
			}
			if ((velocidad.getX() < 0) && (velocidad.getY() > 0) && (animIzqAba.getNumEtapas() > 0)) {
				super.getAnimacionPorDefecto().reiniciar();
				animIzquierda.reiniciar();
				animDerecha.reiniciar();
				animArriba.reiniciar();
				animAbajo.reiniciar();
				animIzqAba.actualizar(dt);
				animIzqArr.reiniciar();
				animDerAba.reiniciar();
				animDerArr.reiniciar();
				return;
			}
			if ((velocidad.getX() < 0) && (velocidad.getY() > 0) && (animIzqArr.getNumEtapas() > 0)) {
				super.getAnimacionPorDefecto().reiniciar();
				animIzquierda.reiniciar();
				animDerecha.reiniciar();
				animArriba.reiniciar();
				animAbajo.reiniciar();
				animIzqAba.reiniciar();
				animIzqArr.actualizar(dt);
				animDerAba.reiniciar();
				animDerArr.reiniciar();
				return;
			}
		}
		if ((velocidad.getY() < 0) && (animArriba.getNumEtapas() > 0)) {
			super.getAnimacionPorDefecto().reiniciar();
			animIzquierda.reiniciar();
			animDerecha.reiniciar();
			animArriba.actualizar(dt);
			animAbajo.reiniciar();
			animIzqAba.reiniciar();
			animIzqArr.reiniciar();
			animDerAba.reiniciar();
			animDerArr.reiniciar();
			return;
		}
		if ((velocidad.getY() > 0) && (animAbajo.getNumEtapas() > 0)) {
			super.getAnimacionPorDefecto().reiniciar();
			animIzquierda.reiniciar();
			animDerecha.reiniciar();
			animArriba.reiniciar();
			animAbajo.actualizar(dt);
			animIzqAba.reiniciar();
			animIzqArr.reiniciar();
			animDerAba.reiniciar();
			animDerArr.reiniciar();
			return;
		}
		if ((velocidad.getX() < 0) && (animIzquierda.getNumEtapas() > 0)) {
			super.getAnimacionPorDefecto().reiniciar();
			animIzquierda.actualizar(dt);
			animDerecha.reiniciar();
			animArriba.reiniciar();
			animAbajo.reiniciar();
			animIzqAba.reiniciar();
			animIzqArr.reiniciar();
			animDerAba.reiniciar();
			animDerArr.reiniciar();
			return;
		}
		if ((velocidad.getX() > 0) && (animDerecha.getNumEtapas() > 0)) {
			super.getAnimacionPorDefecto().reiniciar();
			animIzquierda.reiniciar();
			animDerecha.actualizar(dt);
			animArriba.reiniciar();
			animAbajo.reiniciar();
			animIzqAba.reiniciar();
			animIzqArr.reiniciar();
			animDerAba.reiniciar();
			animDerArr.reiniciar();
			return;
		}
		super.actualizarAnimacion(dt);
		animIzquierda.reiniciar();
		animDerecha.reiniciar();
		animArriba.reiniciar();
		animAbajo.reiniciar();
		animIzqAba.reiniciar();
		animIzqArr.reiniciar();
		animDerAba.reiniciar();
		animDerArr.reiniciar();
	}
	
	@Override
	/**
	 * Pinta el estado actual del objeto.
	 */
	public void paint(Graphics g) {
		if (velocidad.getX() == 0) {
			super.paint(g);
		}
		if ((velocidad.getX() < 0) && (animIzquierda.getNumEtapas() > 0)) {
			g.drawImage(animIzquierda.getEstadoActual().getImage(), getXInt(), getYInt(), null);
		} else if ((velocidad.getX() < 0) && (animIzquierda.getNumEtapas() == 0)) {
			super.paint(g);
		}
		if ((velocidad.getX() > 0) && (animDerecha.getNumEtapas() > 0)) {
			g.drawImage(animDerecha.getEstadoActual().getImage(), getXInt(), getYInt(), null);
		} else if ((velocidad.getX() > 0) && (animDerecha.getNumEtapas() == 0)) {
			super.paint(g);
		}
	}
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia la izquierda.
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimIzq(ImageIcon img) {
		animIzquierda.agregarEtapa(img);
	}
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia la derecha.
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimDch(ImageIcon img) {
		animDerecha.agregarEtapa(img);
	}
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia arriba
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimArr(ImageIcon img) {
		animArriba.agregarEtapa(img);
	}
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia abajo.
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimAba(ImageIcon img) {
		animAbajo.agregarEtapa(img);
	}
	
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia la izquierda
	 * y hacia arriba.
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimIzqArr(ImageIcon img) {
		animIzqArr.agregarEtapa(img);
	}
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia la derecha
	 * y hacia arriba.
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimDerArr(ImageIcon img) {
		animDerArr.agregarEtapa(img);
	}
	
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia la izquierda
	 * y hacia abajo.
	 * @param img ImageIcon
	 */
	public void agregarEtapaIzqAba(ImageIcon img) {
		animIzqAba.agregarEtapa(img);
	}
	
	
	/**
	 * Agrega una etapa (frame) a la animacion de la EntidadMovil al moverse hacia la derecha
	 * y hacia abajo.
	 * @param img ImageIcon
	 */
	public void agregarEtapaAnimDerAba(ImageIcon img) {
		animDerAba.agregarEtapa(img);
	}
	
	public double getVelocidadX() {
		return velocidad.getX();
	}

	public void setVelocidadX(double dx) {
		this.velocidad.setX(dx);
	}

	public double getVelocidadY() {
		return velocidad.getY();
	}

	public void setVelocidadY(double dy) {
		this.velocidad.setY(dy);
	}

	public Animacion getAnimIzquierda() {
		return animIzquierda;
	}

	public void setAnimIzquierda(Animacion animIzquierda) {
		this.animIzquierda = animIzquierda;
	}

	public Animacion getAnimDerecha() {
		return animDerecha;
	}

	public void setAnimDerecha(Animacion animDerecha) {
		this.animDerecha = animDerecha;
	}

	public Coordenadas2D getVelocidad() {
		return velocidad;
	}

	public void setVelocidad(Coordenadas2D velocidad) {
		this.velocidad = velocidad;
	}

	public Coordenadas2D getAceleracion() {
		return aceleracion;
	}

	public void setAceleracion(Coordenadas2D aceleracion) {
		this.aceleracion = aceleracion;
	}

	public Animacion getAnimArriba() {
		return animArriba;
	}

	public void setAnimArriba(Animacion animArriba) {
		this.animArriba = animArriba;
	}

	public Animacion getAnimAbajo() {
		return animAbajo;
	}

	public void setAnimAbajo(Animacion animAbajo) {
		this.animAbajo = animAbajo;
	}

	public Animacion getAnimIzqArr() {
		return animIzqArr;
	}

	public void setAnimIzqArr(Animacion animIzqArr) {
		this.animIzqArr = animIzqArr;
	}

	public Animacion getAnimIzqAba() {
		return animIzqAba;
	}

	public void setAnimIzqAba(Animacion animIzqAba) {
		this.animIzqAba = animIzqAba;
	}

	public Animacion getAnimDerArr() {
		return animDerArr;
	}

	public void setAnimDerArr(Animacion animDerArr) {
		this.animDerArr = animDerArr;
	}

	public Animacion getAnimDerAba() {
		return animDerAba;
	}

	public void setAnimDerAba(Animacion animDerAba) {
		this.animDerAba = animDerAba;
	}

	public boolean isAnimDiagonales() {
		return animDiagonales;
	}

	public void setAnimDiagonales(boolean animDiagonales) {
		this.animDiagonales = animDiagonales;
	}


}
